#include <QDebug>
#include <QWheelEvent>

#include <osg/Geometry>

#include "GLDrawer.h"

AdapterWidget::AdapterWidget(QWidget* parent) : QGLWidget(parent)
{
    _gw = new osgViewer::GraphicsWindowEmbedded(0,0,width(),height());
    setFocusPolicy(Qt::ClickFocus);
}

void AdapterWidget::resizeGL(int width, int height)
{
    _gw->getEventQueue()->windowResize(0, 0, width, height);
    _gw->resized(0, 0, width, height);
}

void AdapterWidget::keyPressEvent(QKeyEvent* event)
{
    _gw->getEventQueue()->keyPress((osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data()));
}

void AdapterWidget::keyReleaseEvent(QKeyEvent* event)
{
    _gw->getEventQueue()->keyRelease((osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data()));
}

void AdapterWidget::mousePressEvent(QMouseEvent* event)
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
	event->ignore();
	updateGL();
}

void AdapterWidget::mouseReleaseEvent(QMouseEvent* event)
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
	updateGL();
}

void AdapterWidget::mouseMoveEvent(QMouseEvent* event)
{
    _gw->getEventQueue()->mouseMotion(event->x(), event->y());
	updateGL();
}

void AdapterWidget::wheelEvent(QWheelEvent *event)
{    
	_gw->getEventQueue()->mouseScroll((event->delta()>0) ?             
	osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN);
	updateGL();
}

GLDrawer::GLDrawer(QWidget *parent) : AdapterWidget(parent)
{
	getCamera()->setViewport(new osg::Viewport(0, 0, width(), height()));
    getCamera()->setGraphicsContext(getGraphicsWindow());
	getCamera()->setClearColor(osg::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
	setThreadingModel(osgViewer::Viewer::SingleThreaded);

	osg::Geode* geode = new osg::Geode;

	geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

	osg::Geometry* geometry = new osg::Geometry;
    osg::Vec3Array* vertices = new osg::Vec3Array(12);
    (*vertices)[0].set(-10, 0, 10);
    (*vertices)[1].set(10, 0, 10);
    (*vertices)[2].set(-10, 0, 0);
    (*vertices)[3].set(10, 0, 0);
    (*vertices)[4].set(-10, 0, -10);
    (*vertices)[5].set(10, 0, -10);
    (*vertices)[6].set(10, 0, -10);
    (*vertices)[7].set(10, 0, 10);
	(*vertices)[8].set(0, 0, -10);
	(*vertices)[9].set(0, 0, 10);
	(*vertices)[10].set(-10, 0, -10);
	(*vertices)[11].set(-10, 0, 10);
	geometry->setVertexArray(vertices);
    osg::Vec4Array* colors = new osg::Vec4Array;
	colors->push_back(osg::Vec4(0.3f, 0.3f, 0.3f, 1.0f));
    geometry->setColorArray(colors);
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,12));
	geode->addDrawable(geometry);

	geometry = new osg::Geometry;
    vertices = new osg::Vec3Array(2);
    (*vertices)[0].set(0, 0, 0);
    (*vertices)[1].set(0, 5, 0);
	geometry->setVertexArray(vertices);
    colors = new osg::Vec4Array;
	colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
    geometry->setColorArray(colors);
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2));
	geode->addDrawable(geometry);

	geometry = new osg::Geometry;
    vertices = new osg::Vec3Array(2);
    (*vertices)[0].set(10, 0, 0);
    (*vertices)[1].set(15, 0, 0);
	geometry->setVertexArray(vertices);
    colors = new osg::Vec4Array;
	colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
    geometry->setColorArray(colors);
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2));
	geode->addDrawable(geometry);

	geometry = new osg::Geometry;
    vertices = new osg::Vec3Array(2);
    (*vertices)[0].set(0, 0, 10);
    (*vertices)[1].set(0, 0, 15);
	geometry->setVertexArray(vertices);
    colors = new osg::Vec4Array;
	colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
    geometry->setColorArray(colors);
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
	geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,2));
	geode->addDrawable(geometry);

	getCamera()->setEventCallback(new EventHandler(this));

	setSceneData(geode);
	setViewMode(Perspective);
}

void GLDrawer::paintGL()
{
	frame();
}

void GLDrawer::setViewMode(ViewMode mode)
{
	bool change = (viewMode != mode);
	if (change)
	{
		float ratio = (float)width() / (float)height();
		switch (mode)
		{
		case Perspective:
			cameraController = new CControllerPerspective(getCamera(), ratio);
			break;
		case Isometric:
			cameraController = new CControllerIsometric(getCamera(), ratio);
			break;
		case Top:
			cameraController = new CControllerTopView(getCamera(), ratio);
			break;
		case Down:
			cameraController = new CControllerBottomView(getCamera(), ratio);
			break;
		case Left:
			cameraController = new CControllerLeftView(getCamera(), ratio);
			break;
		case Right:
			cameraController = new CControllerRightView(getCamera(), ratio);
			break;
		case Front:
			cameraController = new CControllerFrontView(getCamera(), ratio);
			break;
		case Back:
			cameraController = new CControllerBackView(getCamera(), ratio);
			break;
		}
	}
}
